feat(billing): extract email listeners + ship generic templates#3747
Conversation
- New `modules/billing/billing.email.js` exports `setupBillingEmails()` which wires
`meter.threshold_crossed` (80%/100%) and `payment.failed` event listeners,
plus `resolveOrgAdminEmails` and `sendBillingEmail` helpers
- `billing.init.js` imports and calls `setupBillingEmails()` from the new file
- Ship 3 generic HTML templates in `config/templates/billing-*.html` using
`{{appName}}` placeholder (resolved from `config.app.title` at send-time);
zero hardcoded branding — every downstream gets working billing emails out of the box
- Downstream override: place same-named files in downstream's `config/templates/`;
they shadow devkit defaults via template-resolution glob-merge
- Port + de-trawlify 18 unit tests covering both listener paths (threshold + payment.failed)
- Subjects are now config-driven (`${config.app.title} weekly quota reached`)
so each downstream gets its own app name in email subjects
Closes #3746
|
Warning Review limit reached
More reviews will be available in 37 minutes and 54 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (8)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3747 +/- ##
==========================================
+ Coverage 90.03% 90.11% +0.07%
==========================================
Files 148 149 +1
Lines 4898 4936 +38
Branches 1546 1564 +18
==========================================
+ Hits 4410 4448 +38
Misses 383 383
Partials 105 105
Flags with carried forward coverage won't be shown. Click here to find out more. Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
Summary
Trawl had
meter.threshold_crossed+payment.failedlisteners + email helpers (resolveOrgAdminEmails,sendBillingEmail) inline inbilling.init.js. These are universal — every downstream running the billing module wants billing quota warnings and payment failure notifications.modules/billing/billing.email.jsexportssetupBillingEmails()which wires the two listeners + both helpers. Called frombilling.init.js.config/templates/billing-quota-warning-80.html,billing-quota-reached-100.html,billing-payment-failed.htmlwith{{appName}}placeholder — zero hardcoded branding, fully config-driven viaconfig.app.title.config/templates/— they shadow devkit defaults via template-resolution glob-merge. Trawl's own branded templates already exist and still win.${config.app.title} weekly quota reached— each downstream gets its own app name.billing.email.jsso boot-validator tests remain isolated.Test plan
billing.init.email-alerts.unit.tests.js— 18 tests, all passingtrawl/Trawlreferences in any new file{{appName}}throughout, no hardcoded brandingReferences
2026-05-30-trawl-devkit-perfect-alignment.mdTask A.2